{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当前真正的问题是 头文件间的循环 `#include`，通过 `前置声明` + `在 .cpp 中包含对方头文件` 可以打破。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**反例：直接互相 `#include`，导致循环依赖**\n",
    "\n",
    "\n",
    "如果只要在某个源文件里写 `#include \"A.h\"`，编译器就会经历：\n",
    "\n",
    "1. 读 A.h → 看到 `#include \"B.h\"` → 去读 B.h。\n",
    "2. 读 B.h → 看到 `#include \"A.h\"` → 又回去读 A.h。\n",
    "3. 虽然有 `#pragma once` 阻止无限递归，但在 B.h 中第一次遇到 `class A` 时，编译器尚未看到完整定义，某些用法会报错，而且两个头需要彼此都重新编译，耦合极强。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// A.h\n",
    "#pragma once\n",
    "#include \"B.h\"\n",
    "\n",
    "class A {\n",
    "public:\n",
    "    void foo(B* b);\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// B.h\n",
    "#pragma once\n",
    "#include \"A.h\"\n",
    "\n",
    "class B {\n",
    "public:\n",
    "    void bar(A* a);\n",
    "};"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**正例：使用前置声明，真正需要完整定义时再 `#include`**\n",
    "- 头文件只保留前置声明，减少彼此的编译耦合。\n",
    "- 真正需要完整类型信息（访问成员、创建对象等）时，放在 .cpp 中再 `#include` 对方头文件。\n",
    "- 这样既不会产生编译期循环依赖，也能保持接口简洁清晰。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// A.h\n",
    "#pragma once\n",
    "\n",
    "class B;  // 前置声明\n",
    "\n",
    "class A {\n",
    "public:\n",
    "    void foo(B* b);  // 仅指针/引用即可使用前置声明\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// B.h\n",
    "#pragma once\n",
    "\n",
    "class A;  // 前置声明\n",
    "\n",
    "class B {\n",
    "public:\n",
    "    void bar(A* a);\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// A.cpp\n",
    "#include \"A.h\"\n",
    "#include \"B.h\"\n",
    "\n",
    "void A::foo(B* b) {\n",
    "    // 此处需要 B 的完整定义，所以在实现文件里包含 B.h\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// B.cpp\n",
    "#include \"B.h\"\n",
    "#include \"A.h\"\n",
    "\n",
    "void B::bar(A* a) {\n",
    "    // 同理，这里才真正用到 A 的定义\n",
    "}"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "name": "C++17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
